/*

 Copyright 2012 Peter Dornbach.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
   
*/

package com.dornbachs.zebra.guitarear;

import java.util.Arrays;
import java.util.List;

public class Level {
	public static final int DIMENSIONS = 5; 

	public static final int IDX_WHAT = 0;
	public static final int IDX_CHORDS = 1;
	public static final int IDX_NUM_CHORDS = 2;
	public static final int IDX_STRUMMING = 3;
	public static final int IDX_INSTRUMENT = 4;
	
  public boolean isAllowed() {
  	// At chord level 0 we only have major chords, so that would be trivial :)
  	if (_levels[IDX_WHAT] == 0 && _levels[IDX_CHORDS] == 0) {
  		return false;
  	}
  	// At chord levels 0 and 1 we only have 3 chords that fit on the same scale.
  	if (_levels[IDX_CHORDS] < 2 && _levels[IDX_NUM_CHORDS] >= 3) {
  		return false;
  	}
  	return true;
  }
	
	public int get(int idx) {
		return _levels[idx];
	}
	
	public boolean canGrow(int idx) {
		if (_levels[idx] + 1 >= LEVEL_LIMITS[idx]) {
			return false;
		}
		if (_levels[IDX_WHAT] == 0 && _levels[IDX_CHORDS] == 0) {
			return idx == IDX_WHAT || idx == IDX_CHORDS;
		}
		return true;
	}
	
	public boolean lessOrEqual(Level other) {
		for (int i = 0; i < DIMENSIONS; ++i) {
			if (_levels[i] > other._levels[i]) {
				return false;
			}
		}
		return true;
	}
	
	public void set(int idx, int value) {
		_levels[idx] = value;
	}
	
	public int getWhatLevel() {
		return _levels[IDX_WHAT];
	}
	
	public int getChordShapeLevel() {
		return _levels[IDX_CHORDS];
	}
	
	public int getStrummingLevel() {
		return _levels[IDX_STRUMMING];
	}
	
	public int getNumChords() {
		return _levels[IDX_NUM_CHORDS] + 1;
	}
	
	public String getInstrumentName() {
		return INSTRUMENT_NAMES[_levels[IDX_INSTRUMENT]];
	}
	
	public boolean reduceChords() {
		return _levels[IDX_INSTRUMENT] >= 3;
	}
	
	public void trim(Level other) {
		for (int i = 0; i < DIMENSIONS; i++) {
			_levels[i] = Math.min(_levels[i], other._levels[i]);
		}
	}
	
	public static Level intersect(List<Level> levels) {
		Level l = levels.get(0).clone();
		for (int i = 1; i < levels.size(); ++i) {
			l.trim(levels.get(i));
		}
		return l;
	}
	
	public int score() {
		int result = 1;
		for (int l: _levels) {
			result *= (l + 1);
		}
		return result;
	}
	
	@Override
	public Level clone() {
		Level result = new Level();
		System.arraycopy(_levels, 0, result._levels, 0, DIMENSIONS);
		return result;
	}
	
	@Override
	public boolean equals(Object other) {
		if (other instanceof Level) {
			Level l = (Level)other;
			return Arrays.equals(_levels, l._levels);
		}
		return false;
	}
	
	public String toString() {
		return Util.join(",", _levels);
	}

	public static Level fromString(String str) {
		String[] s = str.split(",");
		assert s.length == DIMENSIONS;
		Level l = new Level();
		for (int i = 0; i < DIMENSIONS; ++i) {
			l._levels[i] = Integer.parseInt(s[i]);
		}
		return l;
	}
	
	private static final String[] INSTRUMENT_NAMES = {
		"nylon",
		"clean",
		"lead",
		"overdrive",
	};
	
	// For each value there should be enough strings to describe the settings on the UI.
	private static final int[] LEVEL_LIMITS = {
		2,
		ChordShape.MAX_LEVEL + 1,
		4,
		3,
		INSTRUMENT_NAMES.length,
	};
	
	private int[] _levels = new int[DIMENSIONS];
} 